// 配置
const DEFAULT_CONFIG = {
    baseFontSize: 16,
    enablePerformanceMonitor: false,
    cacheCapacity: 1000,
    skipSelectors: ['.no-rem', '[data-skip-rem]'],
    skipFlag: 'skip-to-rem'
}

// 匹配px单位的正则表达式
const PX_REGEX = /(\d*\.?\d+)px/g

// LRU缓存实现
class LRUCache {
    constructor(capacity) {
        this.cache = new Map()
        this.capacity = capacity
    }

    get(key) {
        if (!this.cache.has(key)) return undefined
        const value = this.cache.get(key)
        this.cache.delete(key)
        this.cache.set(key, value)
        return value
    }

    put(key, value) {
        if (this.cache.has(key)) {
            this.cache.delete(key)
        } else if (this.cache.size >= this.capacity) {
            this.cache.delete(this.cache.keys().next().value)
        }
        this.cache.set(key, value)
    }
}

// 性能监控优化
const performanceMonitor = {
    enabled: false,
    startTime: 0,
    metrics: {
        totalExecutes: 0,
        averageTime: 0,
        maxTime: 0
    },
    create() {
        this.log()
        this.enabled = true
    },

    start() {
        if (!this.enabled) return
        this.startTime = performance.now()
    },

    end() {
        if (!this.enabled) return
        const duration = performance.now() - this.startTime
        this.recordMetrics(duration)
    },

    recordMetrics(duration) {
        this.metrics.totalExecutes++
        this.metrics.averageTime = (this.metrics.averageTime * (this.metrics.totalExecutes - 1) + duration) / this.metrics.totalExecutes
        this.metrics.maxTime = Math.max(this.metrics.maxTime, duration)
    },

    log() {
        setTimeout(() => {
            console.log(`总转换数量: ${ this.metrics.totalExecutes },平均耗时: ${ this.metrics.averageTime.toFixed(2) }ms, 最大耗时: ${ this.metrics.maxTime.toFixed(2) }ms`)
            this.log()
        }, 10000)
    }
}

if (DEFAULT_CONFIG.enablePerformanceMonitor) performanceMonitor.create()

// 缓存实例
const pxToRemCache = new LRUCache(DEFAULT_CONFIG.cacheCapacity)

// 工具函数
const utils = {
    pxToRem(px, base) {
        if (parseFloat(px) === 0) return '0'
        const cacheKey = `${ px }-${ base }`
        let result = pxToRemCache.get(cacheKey)
        if (result) return result
        const value = parseFloat(px)
        result = isNaN(value) ? px : (value / base) + 'rem'
        pxToRemCache.put(cacheKey, result)
        return result
    },

    convertValue(value, base, skipProps = []) {
        if (typeof value !== 'string') return value
        const cacheKey = `${ value }-${ base }-${ skipProps.join(',') }`

        let result = pxToRemCache.get(cacheKey)
        if (result) return result

        const declarations = value.split(';').filter(Boolean)
        result = declarations.map(declaration => {
            const [prop, val] = declaration.split(':').map(s => s.trim())
            if (skipProps.includes(prop)) return declaration
            const convertedVal = val.replace(PX_REGEX, (match, px) => utils.pxToRem(px + 'px', base))
            return `${ prop }: ${ convertedVal }`
        }).join(';')

        pxToRemCache.put(cacheKey, result)
        return result
    },

    matchesSelector(el, selectors) {
        if (!selectors?.length) return false
        return selectors.some(selector => el.matches(selector))
    },

    shouldSkip(element, skipSelectors) {
        if (utils.matchesSelector(element, skipSelectors)) return true
        let current = element
        while (current) {
            if (current.hasAttribute(DEFAULT_CONFIG.skipFlag)) return true
            current = current.parentElement
        }
        return false
    },

    processBindingValue(binding, isDeep = false) {
        let base = DEFAULT_CONFIG.baseFontSize
        let skipProps = []
        let skipSelectors = []

        if (Array.isArray(binding.value)) {
            if (isDeep) skipSelectors = Array.from(new Set(binding.value))
            else skipProps = Array.from(new Set(binding.value))
        } else if (typeof binding.value === 'object') {
            const {base: customBase, skipProps: customSkipProps = [], skipSelectors: customSkipSelect = []} = binding.value
            base = customBase || base
            skipProps = Array.from(new Set(customSkipProps))
            skipSelectors = Array.from(new Set(customSkipSelect))
        }

        return {base, skipProps, skipSelectors}
    }
}

// 样式代理处理器
const styleHandler = {
    createProxy(el, base, skipProps = []) {
        try {

            const handler = {
                get(target, prop) {
                    const value = target[prop]
                    if (typeof value === 'function') {
                        return value.bind(target)
                    }
                    return value
                },
                set(target, prop, value) {
                    performanceMonitor.start()
                    if (prop === 'cssText') {
                        value = utils.convertValue(value, base, skipProps)
                    } else if (typeof value === 'string' && !skipProps.includes(prop)) {
                        if (prop.startsWith('--')) {
                            value = value.replace(PX_REGEX, (match, px) => utils.pxToRem(px + 'px', base))
                            target.setProperty(prop, value)
                            return true
                        } else {
                            value = value.replace(PX_REGEX, (match, px) => utils.pxToRem(px + 'px', base))
                        }
                    }
                    performanceMonitor.end()
                    return Reflect.set(target, prop, value)
                }
            }

            const styleProxy = new Proxy(el.style, handler)

            const extendedProxy = new Proxy(styleProxy, {
                get(target, prop) {
                    if (prop === 'setProperty') {
                        return function (name, value, priority) {
                            if (typeof value === 'string' && !skipProps.includes(name)) {
                                value = value.replace(PX_REGEX, (match, px) => utils.pxToRem(px + 'px', base))
                            }
                            return target.setProperty(name, value, priority)
                        }
                    }
                    return target[prop]
                }
            })

            el._styleProxyConfig = {
                original: el.style,
                proxy: extendedProxy,
                base,
                skipProps
            }

            // 处理初始样式
            const originalStyle = el.getAttribute('style')
            if (originalStyle) {
                el.removeAttribute('style')
                const styleDeclarations = originalStyle.split(';').filter(Boolean)
                styleDeclarations.forEach(declaration => {
                    const [prop, val] = declaration.split(':').map(s => s.trim())
                    if (prop.startsWith('--')) {
                        extendedProxy.setProperty(prop, val)
                    } else {
                        extendedProxy[prop] = val
                    }
                })
            }

            Object.defineProperty(el, 'style', {
                get() {
                    return this._styleProxyConfig.proxy
                },
                set(value) {
                    if (typeof value === 'string') {
                        this._styleProxyConfig.proxy.cssText = value
                    }
                },
                configurable: true
            })

            return extendedProxy
        } catch (error) {
            console.error('Failed to create style proxy:', error)
            return el.style
        }
    },

    removeProxy(el) {
        try {
            if (el._styleProxyConfig) {
                Object.defineProperty(el, 'style', {
                    value: el._styleProxyConfig.original,
                    writable: true,
                    configurable: true
                })
                delete el._styleProxyConfig
            }
        } catch (error) {
            console.error('Failed to remove style proxy:', error)
        }
    }
}
// 指令实现
const pxToRemDirectiveFunc = (el, binding) => {
    const {base, skipProps} = utils.processBindingValue(binding)

    if (!el._styleProxyConfig ||
        el._styleProxyConfig.base !== base ||
        JSON.stringify(el._styleProxyConfig.skipProps) !== JSON.stringify(skipProps)) {
        styleHandler.createProxy(el, base, skipProps)
    }

}

const pxToRemDeepDirectiveFunc = (el, binding, config) => {
    const {base, skipProps, skipSelectors} = utils.processBindingValue(binding, true)
    const skipSelectorsAll = [
        ...config.skipSelectors,
        ...skipSelectors
    ]


    function processElement(element) {
        if (utils.shouldSkip(element, skipSelectorsAll)) return

        if (!element._styleProxyConfig ||
            element._styleProxyConfig.base !== base ||
            JSON.stringify(element._styleProxyConfig.skipProps) !== JSON.stringify(skipProps)) {
            styleHandler.createProxy(element, base, skipProps)
        }

        Array.from(element.children).forEach(child => processElement(child))
    }

    processElement(el)
}

/**
 * binding.value 支持数组、对象两种格式
 * 数组为排除转换的属性
 * 对象格式为 {base: 自定义基准值, skipProps: 排除转换的属性}
 */
export const pxToRemDirective = {
    mounted: (el, binding) => pxToRemDirectiveFunc(el, binding),
    unmounted: (el) => styleHandler.removeProxy(el)
}

/**
 * binding.value 支持数组、对象两种格式
 * 数组为排除转换的选择器
 * 对象格式为 {base: 自定义基准值, skipProps: 排除转换的属性, skipSelectors: 排除转换的选择器}
 */
export const pxToRemDeepDirective = {
    mounted: (el, binding) => pxToRemDeepDirectiveFunc(el, binding, DEFAULT_CONFIG),
    unmounted: (el) => {
        function removeProxyDeep(element) {
            styleHandler.removeProxy(element)
            Array.from(element.children).forEach(child => removeProxyDeep(child))
        }

        removeProxyDeep(el)
    }
}
